/*
 * Copyright (c) 2018-2999 九五云信息科技有限公司 All rights reserved.
 *
 * https://www.gz-yami.com/
 *
 */

package com.yami.shop.user.comment.service.impl;
import java.util.Date;


import cn.hutool.core.collection.CollUtil;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.yami.shop.bean.event.BatchBindCouponEvent;
import com.yami.shop.bean.model.UserExtension;
import com.yami.shop.bean.param.UserUpdateParam;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.util.Arith;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.dao.UserExtensionMapper;
import com.yami.shop.user.comment.dao.UserBalanceLogMapper;
import com.yami.shop.user.comment.dao.UserBalanceMapper;
import com.yami.shop.user.comment.model.*;
import com.yami.shop.user.comment.service.*;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 余额充值级别表
 *
 * @author YXF
 * @date 2020-09-08 10:42:39
 */
@Service
@Slf4j
@AllArgsConstructor
public class UserBalanceServiceImpl extends ServiceImpl<UserBalanceMapper, UserBalance> implements UserBalanceService {

    private final UserBalanceMapper userBalanceMapper;
    private final UserExtensionMapper userExtensionMapper;
    private final UserBalanceLogMapper userBalanceLogMapper;
    private final UserBalanceCouponService userBalanceCouponService;
    private final ApplicationContext applicationContext;
    private final UserLevelService userLevelService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = "UserBalanceList", key = "'balanceList'")
    public void saveBalance(UserBalance userBalance) {
        userBalanceMapper.insert(userBalance);
        if (CollUtil.isEmpty(userBalance.getCouponList())){
            return;
        }
        userBalanceCouponService.insertBatch(userBalance.getBalanceId(),userBalance.getCouponList());
    }

    @Override
    public void updateBalanceById(UserBalance userBalance) {
        userBalanceMapper.updateById(userBalance);
        UserBalance userBalanceDB = userBalanceMapper.getBalanceInfo(userBalance.getBalanceId(), false);
        Map<Long, Coupon> mapByCouponId = userBalanceDB.getCouponList().stream().collect(Collectors.toMap(Coupon::getCouponId, c -> c));
        List<Coupon> addCoupon = Lists.newArrayList();
        if (CollUtil.isEmpty(userBalance.getCouponList()) && CollUtil.isNotEmpty(userBalanceDB.getCouponList())){
            // 之前赠送优惠券，更新为不赠送优惠券
            userBalanceCouponService.removeByBalanceId(userBalance.getBalanceId());
        }else if (CollUtil.isEmpty(userBalanceDB.getCouponList()) && CollUtil.isNotEmpty(userBalance.getCouponList())){
            // 之前不赠送优惠券，更新为赠送优惠券
            userBalanceCouponService.insertBatch(userBalance.getBalanceId(),userBalance.getCouponList());
        }else {
            //筛选需要删除的优惠券.
            Set<Long> couponIdList = mapByCouponId.keySet();
            List<Coupon> updateList = Lists.newArrayList();
            for(Coupon coupon:userBalance.getCouponList()){
                if (!couponIdList.contains(coupon.getCouponId())){
                    addCoupon.add(coupon);
                    continue;
                }
                Coupon couponDB = mapByCouponId.get(coupon.getCouponId());
                if (Objects.equals(coupon.getCouponNum(),couponDB.getCouponNum())) {
                    couponIdList.remove(coupon.getCouponId());
                    continue;
                }
                updateList.add(coupon);
                couponIdList.remove(coupon.getCouponId());
            }
            if(CollUtil.isNotEmpty(couponIdList)){
                userBalanceCouponService.removeByBalaceIdAndCouponId(userBalance.getBalanceId(), couponIdList);
            }
            if(CollUtil.isNotEmpty(addCoupon)){
                userBalanceCouponService.insertBatch(userBalance.getBalanceId(),addCoupon);
            }
            if (CollUtil.isNotEmpty(updateList)){
                userBalanceCouponService.updateBatchByCoupons(userBalance.getBalanceId(),updateList);
            }
        }
    }

    @Override
    public UserBalance getBalanceInfo(Long balanceId) {
        UserBalance balanceInfo = userBalanceMapper.getBalanceInfo(balanceId, true);
        List<Coupon> couponList = balanceInfo.getCouponList();
        Iterator<Coupon> iterator = couponList.iterator();
        while (iterator.hasNext()){
            Coupon coupon = iterator.next();
            if (Objects.isNull(coupon.getCouponId())) {
                iterator.remove();
            }
        }
        return balanceInfo;
    }

    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = "UserBalanceList", key = "'balanceList'")
    })
    public void removeCacheByBalanceId(Long balanceId) {}

    @Override
    @Cacheable(cacheNames = "UserBalanceList", key = "'balanceList'")
    public List<UserBalance> getBalanceList() {
        return userBalanceMapper.getBalanceList();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void paySuccess(String payNo) {
        UserBalanceLog userBalanceLog = userBalanceLogMapper.selectOne(new LambdaQueryWrapper<UserBalanceLog>().eq(UserBalanceLog::getPayNo, payNo));
        if (Objects.isNull(userBalanceLog)){
            log.info("余额充值订单信息异常,支付单号：" + payNo);
            return;
        }
        UserExtension userExtension = userExtensionMapper.selectOne(new LambdaQueryWrapper<UserExtension>().eq(UserExtension::getUserId, userBalanceLog.getUserId()));
        if (Objects.isNull(userExtension)){
            log.info("余额充值的用户信息异常,用户id：" + userBalanceLog.getUserId() + ",支付单号：" + payNo);
            return;
        }
        //保存用户充值的金额及相关数据
        saveUserBalanceData(userBalanceLog,userExtension);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchUpdateUserBalance(UserUpdateParam param) {
        Double balanceValue = param.getBalanceValue();
        List<String> userIds = param.getUserIds();
        if (Objects.equals(0.0,balanceValue) || CollectionUtils.isEmpty(userIds)){
            return false;
        }
        for (String userId : userIds) {
            UserExtension extension = userExtensionMapper.getByUserId(userId);
            if (Objects.isNull(extension)){
                continue;
            }
            UserExtension update = new UserExtension();
            update.setUserExtensionId(extension.getUserExtensionId());
            Double balance = Objects.nonNull(extension.getBalance())?extension.getBalance(): 0.0;
            Double totalBalance = Objects.nonNull(extension.getTotalBalance())? extension.getTotalBalance(): 0.0;
            if (balanceValue > 0) {
                // 用户总余额不减少
                balance = Arith.add(balance,balanceValue);
                update.setBalance(balance);
            }
            totalBalance = Arith.add(totalBalance,balanceValue);
            if(totalBalance < 0){
//                throw new YamiShopBindException("yami.user.balance.check");
                //修改金额过小直接设0，用户总余额不减少
                totalBalance = 0.0;
            }
            update.setTotalBalance(totalBalance);
            userExtensionMapper.updateById(update);
            // 添加日志
            UserBalanceLog userBalanceLog = new UserBalanceLog();
            userBalanceLog.setUserId(userId);
            userBalanceLog.setCreateTime(new Date());
            userBalanceLog.setChangeBalance(Math.abs(balanceValue));
            userBalanceLog.setIoType(balanceValue>0?1:0);
            userBalanceLog.setType(5);
            userBalanceLogMapper.insert(userBalanceLog);
        }
        return true;
    }

    @Override
    public IPage<UserBalanceLog> getPageByUserId(PageParam<UserBalanceLog> page, String userId) {
        return userBalanceLogMapper.getPageByUserId(page,userId);
    }


    private void saveUserBalanceData(UserBalanceLog userBalanceLog, UserExtension userExtension) {
        //充值余额记录
        UserBalance userBalance = getBalanceInfo(userBalanceLog.getBalanceId());
        userBalanceLog.setChangeBalance(userBalance.getRechargeAmount());
        Double totalBanlance = Objects.isNull(userExtension.getTotalBalance())?0:userExtension.getTotalBalance();
        userBalanceLog.setIsPayed(1);
        userBalanceLogMapper.updateById(userBalanceLog);
        userExtension.setTotalBalance(Arith.add(userBalanceLog.getChangeBalance(),totalBanlance));
        userExtension.setBalance(Arith.add(userExtension.getBalance(),userBalanceLog.getChangeBalance()));
        Double presAmount = userBalance.getPresAmount();
        if (presAmount > 0){
            //余额充值赠送记录
            UserBalanceLog presLog = new UserBalanceLog();
            presLog.setChangeBalance(presAmount);
            presLog.setCreateTime(new Date());
            presLog.setIoType(1);
            presLog.setType(2);
            presLog.setUserId(userExtension.getUserId());
            userBalanceLogMapper.insert(presLog);
            userExtension.setTotalBalance(Arith.add(userExtension.getTotalBalance(),presAmount));
            userExtension.setBalance(Arith.add(userExtension.getBalance(),presAmount));
        }
        //赠送优惠券
        if (CollUtil.isNotEmpty(userBalance.getCouponList())){
            List<Long> couponIds = Lists.newArrayList();
            for (Coupon coupon:userBalance.getCouponList()){
                for (int i=0;i<coupon.getCouponNum();i++){
                    couponIds.add(coupon.getCouponId());
                }
            }
            applicationContext.publishEvent(new BatchBindCouponEvent(couponIds,userExtension.getUserId(),0L));
        }

        //赠送成长值 (若提升等级会对user信息进行更改，所以成长值最后计算，且先保存之前操作的用户信息)
        Integer growth = userBalance.getPresGrowth();
        Integer score = userBalance.getPresScore();
        if (growth > 0 || score > 0){
            userLevelService.addGrowthAndScore(growth, score, userExtension.getUserId(),userBalance.getBalanceId().toString(), userExtension,2);
        }
    }
}
